#ifndef bit_array_HPP__
#define bit_array_HPP__


#include <boost/integer.hpp>
#include <boost/array.hpp>

#include "bit_manip.hpp"

//TODO: ya no es tan necesario...
template <int Bits, std::size_t N>
struct array_helper
{
	typedef typename boost::uint_t<Bits>::least internal_element_type;
	static const std::size_t element_capacity =(sizeof(internal_element_type) * CHAR_BIT) / Bits;	
	static const std::size_t array_size = (N / element_capacity) + (  N % element_capacity == 0 ? 0 : 1 );
};


//template <typename SourceIntegralType, typename TargetIntegralType>
//struct set_impl 
//{
//	template <int Bit>
//	static void impl( TargetIntegralType & elem, SourceIntegralType value, int offset )
//	{
//		set_bit_value(elem, offset+Bit, get_bit_value<Bit>(value));
//	}
//
//	template <int Bit>
//    static void call( TargetIntegralType & elem, SourceIntegralType value, int offset )
//	{
//		impl<Bit>(elem, value, offset);
//		call<Bit-1>(elem, value, offset);
//	}
//
//	template <>
//	static void call<0>( TargetIntegralType & elem, SourceIntegralType value, int offset )
//	{
//		impl<0>(elem, value, offset);
//	}
//};




template <int Bits, std::size_t N>
struct bit_array 
{
	typedef array_helper<Bits, N> helper;
	typedef typename helper::internal_element_type internal_element_type;

	//typedef boost::array<
	//	internal_element_type
	//	, helper::array_size
	//> array_type;

	typedef internal_element_type array_type[helper::array_size];


	//typedef internal_element_type					value_type;            
	//typedef internal_element_type                   iterator;              
	//typedef const internal_element_type*            const_iterator;        
	//typedef std::reverse_iterator<iterator>         reverse_iterator;      
	//typedef std::reverse_iterator<const_iterator>   const_reverse_iterator;
	typedef internal_element_type&                  reference;             
	typedef const internal_element_type&            const_reference;
	typedef std::size_t                             size_type;             
	//typedef std::ptrdiff_t                        difference_type;  
	//array_type elems_;



	//reference operator[](size_type)
	//{
	//
	//}

	const_reference operator[]( size_type index ) const
	{
		//TODO: check index bounds (????)
		return elems_[index];
	}


	inline internal_element_type get( size_type index ) const
	{
		//TODO: check index bounds (????)
		const size_type array_idx = index / helper::element_capacity;
		const size_type elem_idx  = index % helper::element_capacity;

		return (elems_[array_idx] >> (Bits * elem_idx)) & bit::mask<0, Bits>::value;
	}

	//template < size_type Index >
	//inline internal_element_type get() const
	//{
	//	//TODO: check index bounds (????)
	//	const size_type array_idx = Index / helper::element_capacity;
	//	const size_type elem_idx  = Index % helper::element_capacity;

	//	return (elems_[array_idx] >> (Bits * elem_idx)) & bit_mask<0, Bits>::value;
	//}

	template <typename IntegralType>
	inline void set( size_type index, IntegralType value )
	{
		//TODO: check is_integral
		//TODO: check index bounds (????)

		const size_type array_idx = index / helper::element_capacity;
		const size_type elem_idx  = index % helper::element_capacity;

		elems_[array_idx] &= ~(bit::runtime::mask<Bits>::get(elem_idx));
		elems_[array_idx] |= value << (Bits * elem_idx);
		//set_impl<IntegralType, internal_element_type>::call<Bits-1>(elems_[array_idx], value, min_bit);
	}

	//template < size_type Index, typename IntegralType >
	//inline void set( IntegralType value )
	//{
	//	static const size_type array_idx = Index / helper::element_capacity;
	//	static const size_type elem_idx  = Index % helper::element_capacity;

	//	elems_[array_idx] &= ~(bit_mask<elem_idx, Bits>::value);
	//	elems_[array_idx] |= value << (Bits * elem_idx);
	//}

	////TODO: int?
	//template < size_type Index, int Value >
	//inline void set()
	//{
	//	static const size_type array_idx = Index / helper::element_capacity;
	//	static const size_type elem_idx  = Index % helper::element_capacity;

	//	elems_[array_idx] &= ~(bit_mask<elem_idx, Bits>::value);
	//	elems_[array_idx] |= Value << (Bits * elem_idx);
	//}



	//const internal_element_type (&ret() const)[helper::array_size]
	//{
	//	return elems_;
	//} 


//TODO: como exponemos el array interno ?????
//private:
	internal_element_type elems_[helper::array_size];
};

#endif // bit_array_HPP__
